<template>
  <div class="floating-log-viewer" :class="{ 'viewer-open': isOpen }">
    <div class="viewer-panel" v-show="isOpen">
      <div class="viewer-header">
        <div class="viewer-title">
          <el-icon><Document /></el-icon>
          <span>{{ currentFile || '日志文件查看器' }}</span>
        </div>
        <div class="viewer-actions">
          <el-button size="small" @click="closeViewer" type="text">
            <el-icon><Close /></el-icon>
          </el-button>
        </div>
      </div>
      
      <div class="viewer-content">
        <div v-if="loading" class="loading-container">
          <el-icon class="is-loading"><Loading /></el-icon>
          <p>正在加载文件内容...</p>
        </div>
        
        <div v-else-if="error" class="error-container">
          <el-icon><Warning /></el-icon>
          <p>{{ error }}</p>
        </div>
        
        <div v-else-if="fileContent" class="file-content">
          <div class="line-numbers">
            <div 
              v-for="lineNum in totalLines" 
              :key="lineNum"
              class="line-number"
              :class="{ 'highlight': isHighlightedLine(lineNum) }"
            >
              {{ lineNum }}
            </div>
          </div>
          <div class="file-lines" @scroll="syncScroll">
            <div 
              v-for="(line, index) in fileLines" 
              :key="index"
              class="file-line"
              :class="{ 'highlight': isHighlightedLine(index + 1) }"
              :id="`floating-line-${index + 1}`"
            >
              {{ line }}
            </div>
          </div>
        </div>
        
        <div v-else class="empty-content">
          <el-icon><Document /></el-icon>
          <p>请选择一个日志文件查看内容</p>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, watch, nextTick } from 'vue'
import { Document, Close, Warning, Loading } from '@element-plus/icons-vue'
import * as api from '@/api'
import { ElMessage } from 'element-plus'

interface Props {
  isOpen: boolean // 控制查看器是否打开
  sourceFile?: string // 源文件路径
  highlightLine?: number // 要高亮的行号
  componentFilter?: string // 组件筛选
  levelFilter?: string // 级别筛选
}

const props = defineProps<Props>()
const emits = defineEmits(['update:isOpen', 'close'])

// 响应式数据
const loading = ref(false)
const error = ref('')
const fileContent = ref('')
const currentFile = ref('')
const highlightedLines = ref<number[]>([])

// 计算属性
const fileLines = computed(() => {
  if (!fileContent.value) return []
  return fileContent.value.split('\n')
})

const totalLines = computed(() => {
  return fileLines.value.length
})

// 方法
const closeViewer = () => {
  emits('update:isOpen', false)
  emits('close')
}

const isHighlightedLine = (lineNum: number) => {
  return highlightedLines.value.includes(lineNum)
}

const loadFileContent = async () => {
  const filename = props.sourceFile
  if (!filename) {
    fileContent.value = ''
    currentFile.value = ''
    highlightedLines.value = []
    return
  }
  
  loading.value = true
  error.value = ''
  
  try {
    const response = await api.getLogFileContent(filename, props.componentFilter, props.levelFilter)
    
    fileContent.value = (response as any).content
    currentFile.value = filename
    
    // 设置高亮行
    if (props.highlightLine) {
      highlightedLines.value = [props.highlightLine]
    } else {
      highlightedLines.value = []
    }
    
    await nextTick() // 等待DOM更新
    scrollToHighlightedLine()
    
  } catch (err: any) {
    console.error('加载文件内容失败:', err)
    error.value = err.response?.data?.error || err.message || '加载文件内容失败'
    fileContent.value = ''
    currentFile.value = ''
    highlightedLines.value = []
    ElMessage.error(`加载日志文件失败: ${error.value}`)
  } finally {
    loading.value = false
  }
}

const scrollToHighlightedLine = () => {
  if (highlightedLines.value.length > 0) {
    const targetLine = highlightedLines.value[0]
    const targetElement = document.getElementById(`floating-line-${targetLine}`)
    
    if (targetElement) {
      targetElement.scrollIntoView({ 
        behavior: 'smooth', 
        block: 'center' 
      })
      // 同步行号滚动
      setTimeout(syncScroll, 200); // 增加延迟
    }
  }
}

// 同步滚动行号
const syncScroll = () => {
  const fileLinesElement = document.querySelector('.floating-log-viewer .file-lines')
  const lineNumbersElement = document.querySelector('.floating-log-viewer .line-numbers')
  
  if (fileLinesElement && lineNumbersElement) {
    lineNumbersElement.scrollTop = fileLinesElement.scrollTop
  }
}

// 监听 props 变化重新加载文件内容
watch([() => props.sourceFile, () => props.componentFilter, () => props.levelFilter, () => props.isOpen], (newVal, oldVal) => {
  // 仅在 isOpen 变为 true 或者文件/筛选条件变化时加载
  if (props.isOpen && (newVal[0] !== oldVal[0] || newVal[1] !== oldVal[1] || newVal[2] !== oldVal[2] || (newVal[3] === true && oldVal[3] === false))) {
    loadFileContent()
  } else if (!props.isOpen) {
    // 当查看器关闭时，清空内容
    fileContent.value = ''
    currentFile.value = ''
    highlightedLines.value = []
  }
}, { immediate: true })

watch(() => props.highlightLine, (newLine) => {
  if (props.isOpen && newLine) {
    highlightedLines.value = [newLine]
    nextTick(() => {
      scrollToHighlightedLine()
    })
  }
})

// 暴露方法给父组件
defineExpose({
  loadFileContent
})
</script>

<style scoped>
.floating-log-viewer {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none; /* 默认不响应事件 */
  z-index: 1000; /* 确保在最上层 */
}

.floating-log-viewer.viewer-open {
  /* pointer-events: auto; /* 打开时响应事件 - 移除此行 */
}

.viewer-panel {
  position: fixed;
  right: 20px;
  bottom: 120px; /* 位于悬浮按钮上方 */
  width: 1200px; /* 宽度加倍 */
  height: 800px; /* 高度加倍 */
  background: white;
  border: 1px solid #e4e7ed;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
  border-radius: 12px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transform: translateX(100%);
  transition: transform 0.3s ease-out, opacity 0.3s ease-out;
  opacity: 0;
  pointer-events: auto; /* 只让面板本身响应事件 */
}

.viewer-open .viewer-panel {
  transform: translateX(0);
  opacity: 1;
}

.viewer-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px 15px;
  background: #f5f7fa;
  border-bottom: 1px solid #e4e7ed;
  flex-shrink: 0;
}

.viewer-title {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 600;
  color: #303133;
  font-size: 15px;
}

.viewer-content {
  flex: 1;
  overflow: hidden;
  position: relative;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.loading-container,
.error-container,
.empty-content {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100%;
  color: #909399;
  gap: 10px;
}

.error-container {
  color: #f56c6c;
}

.file-content {
  display: flex;
  height: 100%;
  overflow: hidden;
  min-height: 0;
}

.line-numbers {
  width: 60px;
  background: #f0f2f5;
  border-right: 1px solid #e4e7ed;
  overflow-y: auto;
  font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
  font-size: 12px;
  color: #909399;
  text-align: right;
  padding: 8px 0;
  flex-shrink: 0;
}

.line-number {
  padding: 2px 8px;
  height: 18px;
  line-height: 18px;
}

.line-number.highlight {
  background: #e6f7ff;
  color: #1890ff;
  font-weight: 600;
}

.file-lines {
  flex: 1;
  overflow-y: auto;
  font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
  font-size: 12px;
  line-height: 18px;
  padding: 8px 0;
}

.file-line {
  padding: 2px 12px;
  white-space: pre-wrap;
  word-break: break-all;
}

.file-line.highlight {
  background: #e6f7ff;
  border-left: 3px solid #1890ff;
  padding-left: 9px;
}

.is-loading {
  animation: spin 1s linear infinite;
}

@keyframes spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}

@media (max-width: 768px) {
  .viewer-panel {
    width: 90%;
    right: 5%;
    left: 5%;
    bottom: 100px;
    height: 300px;
  }
}
</style>